home *** CD-ROM | disk | FTP | other *** search
/ Hardcore Visual Basic 5.0 (2nd Edition) / Hardcore Visual Basic 5.0 - Second Edition (1997)(Microsoft Press).iso / Code / LOCALM~1 / FileTool.bas < prev    next >
BASIC Source File  |  1997-06-14  |  16KB  |  419 lines

  1. Attribute VB_Name = "MFileTool"
  2. Option Explicit
  3.  
  4. Public Enum EErrorFileTool
  5.     eeBaseFileTool = 13480      ' FileTool
  6. End Enum
  7.  
  8. Public Enum EWalkModeFile
  9.     ewmfDirs = &H20
  10.     ewmfFiles = &H40
  11.     ewmfBoth = &H20 Or &H40
  12. End Enum
  13.  
  14. Private Declare Function SHFileOperation Lib "shell32.dll" _
  15.     Alias "SHFileOperationA" (lpFileOp As SHFILEOPSTRUCT) As Long
  16.  
  17. Private Type SHFILEOPSTRUCT
  18.     hWnd As Long                ' Window owner of any dialogs
  19.     wFunc As Long               ' Copy, move, rename, or delete code
  20.     pFrom As String             ' Source file
  21.     pTo As String               ' Destination file or directory
  22.     fFlags As Integer           ' Options to control the operations
  23.     fAnyOperationsAbortedLo As Integer ' Indicates partial failure
  24.     fAnyOperationsAbortedHi As Integer
  25.     hNameMappingsLo As Long     ' Array indicating each success
  26.     hNameMappingsHi As Long
  27.     lpszProgressTitleLo As Long ' Title for progress dialog
  28.     lpszProgressTitleHi As Long
  29. End Type
  30.  
  31. Const datMin As Date = #1/1/100#
  32. Const datMax  As Date = #12/31/9999 11:59:59 PM#
  33.  
  34. ' Difference between day zero for VB dates and Win32 dates
  35. ' (or #12-30-1899# - #01-01-1601#)
  36. Const rDayZeroBias As Double = 109205#   ' Abs(CDbl(#01-01-1601#))
  37.  
  38. ' 10000000 nanoseconds * 60 seconds * 60 minutes * 24 hours / 10000
  39. ' comes to 86400000 (the 10000 adjusts for fixed point in Currency)
  40. Const rMillisecondPerDay As Double = 10000000# * 60# * 60# * 24# / 10000#
  41.  
  42. Function Win32ToVbTime(ft As Currency) As Date
  43.     Dim ftl As Currency
  44.     ' Call API to convert from UTC time to local time
  45.     If FileTimeToLocalFileTime(ft, ftl) Then
  46.         ' Local time is nanoseconds since 01-01-1601
  47.         ' In Currency that comes out as milliseconds
  48.         ' Divide by milliseconds per day to get days since 1601
  49.         ' Subtract days from 1601 to 1899 to get VB Date equivalent
  50.         Win32ToVbTime = CDate((ftl / rMillisecondPerDay) - rDayZeroBias)
  51.     Else
  52.         ApiRaise Err.LastDllError
  53.     End If
  54. End Function
  55.  
  56. Function VbToWin32Time(dat As Date) As Currency
  57.     Dim ftl As Currency
  58.     ' Date is days since 1899
  59.     ' Add days from 1601 to 1899 to get Win32 days
  60.     ' Multiply by milliseconds per day to get milliseconds since 1601
  61.     ' That would be nanoseconds if it weren't in Currency
  62.     ftl = CCur((CDbl(dat) + rDayZeroBias) * rMillisecondPerDay)
  63.     ' Call API to convert from local time to UTC time
  64.     If LocalFileTimeToFileTime(ftl, VbToWin32Time) = 0 Then
  65.         ApiRaise Err.LastDllError
  66.     End If
  67. End Function
  68.  
  69. Function FileAnyDateTime(sPath As String, _
  70.                          Optional datCreation As Date = datMin, _
  71.                          Optional datAccess As Date = datMin) As Date
  72.     ' Take the easy way if no optional arguments
  73.     If datCreation = datMin And datAccess = datMin Then
  74.         FileAnyDateTime = VBA.FileDateTime(sPath)
  75.         Exit Function
  76.     End If
  77.             
  78.     Dim fnd As WIN32_FIND_DATA
  79.     Dim ftCreate As FILETIME, ftAccess As FILETIME, ftModify As FILETIME
  80.     Dim hFind As Long, f As Boolean, stime As SYSTEMTIME
  81.     ' Get all three times in UDT
  82.     hFind = FindFirstFile(sPath, fnd)
  83.     If hFind = hInvalid Then ApiRaise Err.LastDllError
  84.     FindClose hFind
  85.     ' Convert them to Visual Basic format
  86.     datCreation = Win32ToVbTime(fnd.ftCreationTime)
  87.     datAccess = Win32ToVbTime(fnd.ftLastAccessTime)
  88.     FileAnyDateTime = Win32ToVbTime(fnd.ftLastWriteTime)
  89. End Function
  90.  
  91. Sub ReplaceFile(sOld As String, sTmp As String)
  92.     Dim fnd As WIN32_FIND_DATA, hFind As Long, hOld As Long, f As Boolean
  93.     ' Get file time and attributes of old file
  94.     hFind = FindFirstFile(sOld, fnd)
  95.     If hFind = hInvalid Then ApiRaise Err.LastDllError
  96.     ' Replace by deleting old and renaming new to old
  97.     Kill sOld
  98.     Name sTmp As sOld
  99.     ' Assign old attributes and time to new file
  100.     hOld = lopen(sOld, OF_WRITE Or OF_SHARE_DENY_WRITE)
  101.     If hOld = hInvalid Then ApiRaise Err.LastDllError
  102.     f = SetFileTime(hOld, fnd.ftCreationTime, _
  103.                     fnd.ftLastAccessTime, fnd.ftLastWriteTime)
  104.     If f Then ApiRaise Err.LastDllError
  105.     lclose hOld
  106.     f = SetFileAttributes(sOld, fnd.dwFileAttributes)
  107.     If f Then ApiRaise Err.LastDllError
  108. End Sub
  109.  
  110. ' Better version of FileCopy (CopyAnyFile) and matching MoveAnyFile,
  111. ' DeleteAnyFile, and RenameAnyFile
  112.  
  113. Function CopyAnyFile(sSrc As String, sDst As String, _
  114.                      Optional Options As Long = 0, _
  115.                      Optional Owner As Long = hNull) As Boolean
  116.     If MUtility.HasShell Then
  117.         Dim fo As SHFILEOPSTRUCT, f As Long
  118.         fo.wFunc = FO_COPY
  119.         Debug.Print TypeName(fo.wFunc)
  120.         fo.pFrom = sSrc
  121.         fo.pTo = sDst
  122.         fo.fFlags = Options
  123.         fo.hWnd = Owner
  124.         ' Mask out invalid flags
  125.         fo.fFlags = fo.fFlags And FOF_COPYFLAGS
  126.         f = SHFileOperation(fo)
  127.         CopyAnyFile = (f = 0)
  128.     Else
  129.         ' For Windows NT 3.51
  130.         On Error Resume Next
  131.         ' FileCopy expects full name of destination file
  132.         FileCopy sSrc, sDst
  133.         If Err Then
  134.             Err = 0
  135.             ' CopyAnyFile can handle destination directory
  136.             sDst = MUtility.NormalizePath(sDst) & _
  137.                    MUtility.GetFileBaseExt(sSrc)
  138.             FileCopy sSrc, sDst
  139.         End If
  140.         ' Enhance further to emulate SHFileOperation options
  141.         ' such as validation and wild cards
  142.         CopyAnyFile = (Err = 0)
  143.     End If
  144. End Function
  145.  
  146. Function MoveAnyFile(sSrc As String, sDst As String, _
  147.                   Optional afOptions As Long = 0, _
  148.                   Optional Owner As Long = hNull) As Boolean
  149.     If MUtility.HasShell Then
  150.         Dim fo As SHFILEOPSTRUCT, f As Long
  151.         fo.wFunc = FO_MOVE
  152.         fo.pFrom = sSrc
  153.         fo.pTo = sDst
  154.         fo.fFlags = afOptions
  155.         fo.hWnd = Owner
  156.         ' Mask out invalid flags
  157.         fo.fFlags = fo.fFlags And FOF_COPYFLAGS
  158.         f = SHFileOperation(fo)
  159.         MoveAnyFile = (f = 0)
  160.     Else
  161.         ' Windows NT 3.51
  162.         On Error Resume Next
  163.         ' Name actually moves
  164.         Name sSrc As sDst
  165.         If Err Then ' Probably you gave directory destination
  166.             Err = 0
  167.             sDst = MUtility.NormalizePath(sDst) & _
  168.                    MUtility.GetFileBaseExt(sSrc)
  169.             Name sSrc As sDst
  170.         End If
  171.         ' Enhance further to emulate SHFileOperation options
  172.         ' such as validation and wild cards
  173.         MoveAnyFile = (Err = 0)
  174.     End If
  175. End Function
  176.  
  177. Function RenameAnyFile(sSrc As String, sDst As String, _
  178.                        Optional Options As Long = 0, _
  179.                        Optional Owner As Long = hNull) As Boolean
  180.     If MUtility.HasShell Then
  181.         Dim fo As SHFILEOPSTRUCT, f As Long
  182.         fo.wFunc = FO_RENAME
  183.         'fo.pFrom = StrPtr(sSrc)
  184.         'fo.pTo = StrPtr(sDst)
  185.         fo.pFrom = sSrc
  186.         fo.pTo = sDst
  187.         fo.fFlags = Options
  188.         fo.hWnd = Owner
  189.         ' Mask out invalid flags
  190.         fo.fFlags = fo.fFlags And FOF_RENAMEFLAGS
  191.         f = SHFileOperation(fo)
  192.         RenameAnyFile = (f = 0)
  193.     Else
  194.         ' Windows NT 3.51
  195.         On Error Resume Next
  196.         Name sSrc As sDst
  197.         RenameAnyFile = (Err = 0)
  198.         ' Enhance further to emulate SHFileOperation options
  199.         ' such as validation and wild cards
  200.     End If
  201. End Function
  202.  
  203. Function DeleteAnyFile(sSrc As String, _
  204.                     Optional Options As Long = 0, _
  205.                     Optional Owner As Long = hNull) As Boolean
  206.     If MUtility.HasShell Then
  207.         Dim fo As SHFILEOPSTRUCT, f As Long
  208.         fo.wFunc = FO_DELETE
  209.         fo.pFrom = sSrc
  210.         ' fo.pTo = sNullStr
  211.         fo.fFlags = Options
  212.         fo.hWnd = Owner
  213.         ' Mask out invalid flags
  214.         fo.fFlags = fo.fFlags And FOF_DELETEFLAGS
  215.         f = SHFileOperation(fo)
  216.         DeleteAnyFile = (f = 0)
  217.     Else
  218.         ' Windows NT 3.51
  219.         On Error Resume Next
  220.         Kill sSrc
  221.         DeleteAnyFile = (Err = 0)
  222.         ' Enhance further to emulate SHFileOperation options
  223.         ' such as validation and wild cards
  224.     End If
  225. End Function
  226.  
  227. Function Files(hFiles As Long, fi As CFileInfo, _
  228.                ByVal sSpec As String, _
  229.                Optional afAttr As Long = 0) As String
  230.     Dim fd As WIN32_FIND_DATA, sName As String, f As Boolean, sPath As String
  231.     
  232.     ' Stop finding and close handle early
  233.     If afAttr = -1 Then
  234.         f = FindClose(hFiles)
  235.         hFiles = 0: Exit Function
  236.     End If
  237.     f = True
  238.     Do
  239.         ' Get first or next file
  240.         If hFiles = 0 Then
  241.             hFiles = FindFirstFile(sSpec, fd)
  242.         Else
  243.             f = FindNextFile(hFiles, fd)
  244.         End If
  245.         If (f = False Or hFiles = INVALID_HANDLE_VALUE) Then
  246.             If Err.LastDllError = ERROR_NO_MORE_FILES Then
  247.                 f = FindClose(hFiles)
  248.             End If
  249.             hFiles = 0: Exit Function
  250.         End If
  251.         ' Keep looping until something matches attributes
  252.     Loop While (afAttr <> vbNormal) And _
  253.                ((afAttr And fd.dwFileAttributes) = 0)
  254.     ' Get file data and return through reference
  255.     sPath = MUtility.GetFileDir(sSpec)
  256.     sName = MUtility.StrZToStr(MBytes.BytesToStr(fd.cFileName))
  257.     fi.CreateFromFile sPath & sName, fd.dwFileAttributes, _
  258.                       fd.nFileSizeLow, fd.ftLastWriteTime, _
  259.                       fd.ftLastAccessTime, fd.ftCreationTime
  260.     Files = sName
  261. End Function
  262.  
  263.  
  264. ' Efficient find files function
  265. Function FindFiles(sTarget As String, _
  266.                    Optional ByVal Start As String) As Collection
  267.  
  268.     ' Statics for less memory use in recursive procedure
  269.     Static sName As String, sSpec As String, nFound As New Collection
  270.     Static fd As WIN32_FIND_DATA, iLevel As Long
  271.     Dim hFiles As Long, f As Boolean
  272.     If Start = sEmpty Then Start = CurDir$
  273.     ' Maintain level to ensure collection is cleared first time
  274.     If iLevel = 0 Then
  275.         Set nFound = Nothing
  276.         Start = MUtility.NormalizePath(Start)
  277.     End If
  278.     iLevel = iLevel + 1
  279.     
  280.     ' Find first file (get handle to find)
  281.     hFiles = FindFirstFile(Start & "*.*", fd)
  282.     f = (hFiles <> INVALID_HANDLE_VALUE)
  283.     Do While f
  284.         sName = MBytes.ByteZToStr(fd.cFileName)
  285.         ' Skip . and ..
  286.         If Left$(sName, 1) <> "." Then
  287.             sSpec = Start & sName
  288.             If fd.dwFileAttributes And vbDirectory Then
  289.                 DoEvents
  290.                 ' Call recursively on each directory
  291.                 FindFiles sTarget, sSpec & "\"
  292.             ElseIf StrComp(sName, sTarget, 1) = 0 Then ' Text comparison
  293.                 ' Store found files in collection
  294.                 nFound.Add sSpec
  295.             End If
  296.         End If
  297.         ' Keep looping until no more files
  298.         f = FindNextFile(hFiles, fd)
  299.     Loop
  300.     f = FindClose(hFiles)
  301.     ' Return the matching files in collection
  302.     Set FindFiles = nFound
  303.     iLevel = iLevel - 1
  304. End Function
  305.  
  306. Function WalkAllFiles(fileit As IUseFile, _
  307.                       Optional ByVal ewmf As EWalkModeFile = ewmfBoth, _
  308.                       Optional ByVal Start As String) As Boolean
  309.  
  310.     ' Statics for less memory use in recursive procedure
  311.     Static sName As String, fd As WIN32_FIND_DATA, iLevel As Long
  312.     Static fi As New CFileInfo
  313.     Dim hFiles As Long, f As Boolean
  314.     If Start = sEmpty Then Start = CurDir$
  315.     ' Maintain level to ensure collection is cleared first time
  316.     If iLevel = 0 Then Start = MUtility.NormalizePath(Start)
  317.     iLevel = iLevel + 1
  318.     
  319.     ' Find first file (get handle to find)
  320.     hFiles = FindFirstFile(Start & "*.*", fd)
  321.     f = (hFiles <> INVALID_HANDLE_VALUE)
  322.     Do While f
  323.         sName = MBytes.ByteZToStr(fd.cFileName)
  324.         ' Skip . and ..
  325.         If Left$(sName, 1) <> "." Then
  326.             ' Create a file info object from file data
  327.             fi.CreateFromFile Start & sName, fd.dwFileAttributes, _
  328.                               fd.nFileSizeLow, fd.ftLastWriteTime, _
  329.                               fd.ftLastAccessTime, fd.ftCreationTime
  330.             If fd.dwFileAttributes And vbDirectory Then
  331.                 If ewmf And ewmfDirs Then
  332.                     ' Let client use directory data
  333.                     WalkAllFiles = fileit.UseFile(iLevel, Start, fi)
  334.                     ' If client returns True, walk terminates
  335.                     If WalkAllFiles Then Exit Function
  336.                 End If
  337.                 ' Call recursively on each directory
  338.                 WalkAllFiles = WalkAllFiles(fileit, ewmf, _
  339.                                             Start & sName & "\")
  340.             Else
  341.                 If ewmf And ewmfFiles Then
  342.                     ' Let client use file data
  343.                     WalkAllFiles = fileit.UseFile(iLevel, Start, fi)
  344.                     ' If client returns True, walk terminates
  345.                     If WalkAllFiles Then Exit Function
  346.                 End If
  347.             End If
  348.         End If
  349.         ' Keep looping until no more files
  350.         f = FindNextFile(hFiles, fd)
  351.     Loop
  352.     f = FindClose(hFiles)
  353.     ' Return the matching files in collection
  354.     iLevel = iLevel - 1
  355. End Function
  356.  
  357. Function WalkFiles(fileit As IUseFile, _
  358.                    Optional ByVal ewmf As EWalkModeFile = ewmfBoth, _
  359.                    Optional ByVal Start As String, _
  360.                    Optional UserData As Variant) As Boolean
  361.  
  362.     Dim sName As String, sSpec As String, fd As WIN32_FIND_DATA
  363.     Dim hFiles As Long, f As Boolean, fi As New CFileInfo
  364.     If Start = sEmpty Then Start = CurDir$
  365.     Start = MUtility.NormalizePath(Start)
  366.     
  367.     ' Find first file (get handle to find)
  368.     hFiles = FindFirstFile(Start & "*.*", fd)
  369.     f = (hFiles <> INVALID_HANDLE_VALUE)
  370.     Do While f
  371.         sName = MBytes.ByteZToStr(fd.cFileName)
  372.         ' Skip . and ..
  373.         If Left$(sName, 1) <> "." Then
  374.             ' Create a file info object from file data
  375.             fi.CreateFromFile Start & sName, fd.dwFileAttributes, _
  376.                               fd.nFileSizeLow, fd.ftLastWriteTime, _
  377.                               fd.ftLastAccessTime, fd.ftCreationTime
  378.             If fd.dwFileAttributes And vbDirectory Then
  379.                 If ewmf And ewmfDirs Then
  380.                     ' Let client use directory data
  381.                     WalkFiles = fileit.UseFile(UserData, Start, fi)
  382.                 End If
  383.             Else
  384.                 If ewmf And ewmfFiles Then
  385.                     ' Let client use file data
  386.                     WalkFiles = fileit.UseFile(UserData, Start, fi)
  387.                 End If
  388.             End If
  389.             ' If client returns True, walk terminates
  390.             If WalkFiles Then Exit Function
  391.         End If
  392.         ' Keep looping until no more files
  393.         f = FindNextFile(hFiles, fd)
  394.     Loop
  395.     f = FindClose(hFiles)
  396. End Function
  397. '
  398.  
  399. #If fComponent = 0 Then
  400. Private Sub ErrRaise(e As Long)
  401.     Dim sText As String, sSource As String
  402.     If e > 1000 Then
  403.         sSource = App.ExeName & ".FileTool"
  404.         Select Case e
  405.         Case eeBaseFileTool
  406.             BugAssert True
  407.        ' Case ee...
  408.        '     Add additional errors
  409.         End Select
  410.         Err.Raise COMError(e), sSource, sText
  411.     Else
  412.         ' Raise standard Visual Basic error
  413.         sSource = App.ExeName & ".VBError"
  414.         Err.Raise e, sSource
  415.     End If
  416. End Sub
  417. #End If
  418.  
  419.